package wells.im.server;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.timeout.IdleStateHandler;
import wells.im.handler.ByteMessageDecoder;
import wells.im.handler.ByteMessageEncoder;

public class Server {
	
	public static void main(String[] args) {
		new Server().bindAppPort();
	}
	/**
	 * 读空闲时间(秒)
	 */
	public static final int READ_IDLE_TIME = 150;

	/**
	 * 写接空闲时间(秒)
	 */
	public static final int WRITE_IDLE_TIME = 120;

	/**
	 * 心跳响应 超时为30秒
	 */
	public static final int PONG_TIME_OUT = 10;

	private Integer appPort = 8080;

	public void bindAppPort() {
		NioEventLoopGroup bossGroup = new NioEventLoopGroup();
		NioEventLoopGroup workerGroup = new NioEventLoopGroup();

		ServerBootstrap bootstrap = new ServerBootstrap();
		bootstrap.group(bossGroup, workerGroup);
		bootstrap.childOption(ChannelOption.TCP_NODELAY, true);
		bootstrap.childOption(ChannelOption.SO_KEEPALIVE, true);
		bootstrap.channel(NioServerSocketChannel.class);

		bootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
			@Override
			public void initChannel(SocketChannel ch) {
				ch.pipeline().addLast(new ByteMessageDecoder());
				ch.pipeline().addLast(new ByteMessageEncoder());
				ch.pipeline().addLast(new LoggingHandler(LogLevel.INFO));
				ch.pipeline().addLast(new IdleStateHandler(READ_IDLE_TIME, WRITE_IDLE_TIME, 0));
			}
		});

		ChannelFuture channelFuture = bootstrap.bind(appPort).syncUninterruptibly();
		channelFuture.channel().newSucceededFuture().addListener(future -> {
			String logBanner = "\n\n"
					+ "* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n"
					+ "*                                                                                   *\n"
					+ "*                                                                                   *\n"
					+ "*                   App Socket Server started on port {}.                        *\n"
					+ "*                                                                                   *\n"
					+ "*                                                                                   *\n"
					+ "* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n";
			// LOGGER.info(logBanner, appPort);
		});
		channelFuture.channel().closeFuture().addListener(future -> this.destroy(bossGroup, workerGroup));
	}

	public void destroy(EventLoopGroup bossGroup, EventLoopGroup workerGroup) {
		if (bossGroup != null && !bossGroup.isShuttingDown() && !bossGroup.isShutdown()) {
			try {
				bossGroup.shutdownGracefully();
			} catch (Exception ignore) {
			}
		}

		if (workerGroup != null && !workerGroup.isShuttingDown() && !workerGroup.isShutdown()) {
			try {
				workerGroup.shutdownGracefully();
			} catch (Exception ignore) {
			}
		}
	}
}
